﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media.Animation;

namespace Gmantis.Controls
{
    public class HierarchicalPresenter : System.Windows.Controls.ItemsControl
    {
        // Fields
        private IList _containers;
        internal ContentPresenter _elementHeaderPresenter;
        private TypeConverter _itemConverter;
        private HierarchicalPresenter _rootPresenter;
        private bool _throwIsMouseOverChanged;
        internal static readonly DependencyProperty ForceMouseOverProperty = DependencyProperty.Register("ForceMouseOver", typeof(bool), typeof(HierarchicalPresenter), new PropertyMetadata(new PropertyChangedCallback(HierarchicalPresenter.OnForceMouseOverPropertyChanged)));
        internal const string HeaderPresenterElementName = "HeaderPresenter";
        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(HierarchicalPresenter), new PropertyMetadata(new PropertyChangedCallback(HierarchicalPresenter.OnHeaderPropertyChanged)));
        public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(HierarchicalPresenter), null);
        public static readonly DependencyProperty IsMouseOverProperty = DependencyProperty.Register("IsMouseOver", typeof(bool), typeof(HierarchicalPresenter), new PropertyMetadata(new PropertyChangedCallback(HierarchicalPresenter.OnIsMouseOverPropertyChanged)));
        public static readonly DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(HierarchicalPresenter), null);
        public static readonly DependencyProperty ItemContainerStyleSelectorProperty = DependencyProperty.Register("ItemContainerStyleSelector", typeof(StyleSelector), typeof(HierarchicalPresenter), null);
        public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(HierarchicalPresenter), null);

        // Events
        public event EventHandler<PropertyChangedEventArgs<bool>> IsMouseOverChanged;

        public event EventHandler<ItemPreparedEventArgs> ItemCleared;

        public event EventHandler<ItemPreparedEventArgs> ItemPrepared;

        // Methods
        public HierarchicalPresenter()
        {
            RoutedEventHandler handler = null;
            DependencyPropertyChangedEventHandler handler2 = null;
            this._throwIsMouseOverChanged = true;
            DefaultStyleKey = typeof(HierarchicalPresenter);
            if (handler == null)
                handler = (param0, param1) => this.ChangeVisualStateCommon(false);

            base.Loaded += handler;
            if (handler2 == null)
                handler2 = (s, a) => this.ChangeVisualStateCommon(true);

            base.IsEnabledChanged += handler2;
            this.SetCustomDefaultValues();
        }

        internal IList<HierarchicalPresenter> All(Func<HierarchicalPresenter, object, bool> criteria, object tag, HierarchicalPresenter startPresenter)
        {
            List<HierarchicalPresenter> matchingItems = new List<HierarchicalPresenter>();
            this.All(matchingItems, criteria, tag, startPresenter);
            return matchingItems;
        }

        private void All(List<HierarchicalPresenter> matchingItems, Func<HierarchicalPresenter, object, bool> criteria, object tag, HierarchicalPresenter startPresenter)
        {
            foreach (object obj2 in startPresenter.Items)
            {
                HierarchicalPresenter container = this.GetContainer(obj2);
                if (criteria(container, tag))
                {
                    matchingItems.Add(container);
                }
                this.All(matchingItems, criteria, tag, container);
            }
        }

        protected void ChangeVisualStateCommon(bool useTransitions)
        {
            if (!base.IsEnabled)
            {
                VisualStateHelper.GoToState(this, "Disabled", useTransitions);
            }
            if (base.IsEnabled && this.ForceMouseOver)
            {
                VisualStateHelper.GoToState(this, "MouseOver", useTransitions);
            }
            if (base.IsEnabled && !this.ForceMouseOver)
            {
                VisualStateHelper.GoToState(this, "Normal", useTransitions);
            }
        }

        protected override void ClearContainerForItemOverride(DependencyObject element, object item)
        {
            base.ClearContainerForItemOverride(element, item);
            ItemPreparedEventArgs e = new ItemPreparedEventArgs
            {
                Element = element,
                Item = item
            };
            this.OnItemCleared(e);
        }

        internal object First(Func<HierarchicalPresenter, object, bool> criteria, object tag, HierarchicalPresenter startPresenter)
        {
            object obj2 = null;
            foreach (object obj3 in startPresenter.Items)
            {
                HierarchicalPresenter container = startPresenter.GetContainer(obj3);
                if (criteria(container, tag))
                {
                    obj2 = container;
                }
                else
                {
                    obj2 = this.First(criteria, tag, container);
                }
                if (obj2 != null)
                {
                    return obj2;
                }
            }
            return obj2;
        }

        internal void ForEach(Action<HierarchicalPresenter, object> action, object tag, HierarchicalPresenter startPresenter)
        {
            foreach (object obj2 in startPresenter.Items)
            {
                HierarchicalPresenter container = startPresenter.GetContainer(obj2);
                action(container, tag);
                this.ForEach(action, tag, container);
            }
        }

        internal HierarchicalPresenter GetContainer(object item)
        {
            HierarchicalPresenter presenter = base.ItemContainerGenerator.ContainerFromItem(item) as HierarchicalPresenter;
            return (presenter ?? (item as HierarchicalPresenter));
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new HierarchicalPresenter();
        }

        private IList<T> GetContainers<T>()
        {
            if (this._containers != null)
            {
                this._containers.Clear();
            }
            else
            {
                this._containers = new List<T>();
            }
            foreach (object obj2 in base.Items)
            {
                object container = this.GetContainer(obj2);
                if ((container != null) && (container is T))
                {
                    this._containers.Add((T)container);
                }
            }
            return (IList<T>)this._containers;
        }

        internal IList<T> GetParentContainers<T>()
        {
            if (this.ParentPresenter == null)
            {
                return new List<T>();
            }
            return this.ParentPresenter.GetContainers<T>();
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        private bool InitializeBranch(HierarchicalPresenter root, HierarchicalPresenter parent, HierarchicalPresenter target, HierarchicalPresenter current)
        {
            bool flag = false;
            if (root != current)
            {
                current.InitializePresenter(root, parent);
            }
            if (current == target)
            {
                return true;
            }
            foreach (object obj2 in current.Items)
            {
                HierarchicalPresenter container = current.GetContainer(obj2);
                flag = this.InitializeBranch(root, current, target, container);
                if (flag)
                {
                    return flag;
                }
            }
            return flag;
        }

        private void InitializeHeaderPresenterPart()
        {
            this._elementHeaderPresenter.Content = this.Header;
        }

        public void InitializeItem(HierarchicalPresenter rootPresenter)
        {
            this.InitializeBranch(rootPresenter, null, this, rootPresenter);
        }

        internal void InitializePresenter(HierarchicalPresenter root, HierarchicalPresenter parent)
        {
            this.ParentPresenter = parent;
            this.RootPresenter = root;
        }

        public bool IsAncestorOf(HierarchicalPresenter descendant)
        {
            return descendant.GetAllParents().Contains(this);
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return (item is HierarchicalPresenter);
        }

        public override void OnApplyTemplate()
        {
            this.OnBeforeApplyTemplate();
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._elementHeaderPresenter = this.GetTemplateChild<ContentPresenter>("HeaderPresenter", false, ref errors);
            if (this._elementHeaderPresenter != null)
            {
                this.InitializeHeaderPresenterPart();
            }
            if (!string.IsNullOrEmpty(errors))
            {
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to HierarchicalPresenter.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.ChangeVisualStateCommon(false);
            }
        }

        private void OnBeforeApplyTemplate()
        {
            if (this._elementHeaderPresenter != null)
            {
                this._elementHeaderPresenter.Content = null;
            }
        }

        private static void OnForceMouseOverPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as HierarchicalPresenter).ChangeVisualStateCommon(true);
        }

        protected virtual void OnHeaderChanged(object oldValue)
        {
            if (this._elementHeaderPresenter != null)
            {
                this._elementHeaderPresenter.Content = this.Header;
            }
        }

        private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HierarchicalPresenter presenter = d as HierarchicalPresenter;
            object oldValue = e.OldValue;
            presenter.OnHeaderChanged(oldValue);
        }

        private static void OnIsMouseOverPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HierarchicalPresenter sender = d as HierarchicalPresenter;
            if ((sender.IsMouseOverChanged != null) && sender._throwIsMouseOverChanged)
            {
                PropertyChangedEventArgs<bool> args = new PropertyChangedEventArgs<bool>
                {
                    OldValue = (bool)e.OldValue,
                    NewValue = (bool)e.NewValue
                };
                sender.IsMouseOverChanged(sender, args);
            }
        }

        protected internal virtual void OnItemCleared(ItemPreparedEventArgs e)
        {
            if (this.ItemCleared != null)
            {
                this.ItemCleared(this, e);
            }
        }

        protected internal virtual void OnItemPrepared(ItemPreparedEventArgs e)
        {
            if (this.ItemPrepared != null)
            {
                this.ItemPrepared(this, e);
            }
        }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            HeaderedContentControl container = element as HeaderedContentControl;
            if (container != null)
            {
                this.PrepareHeaderedContentControlForItem(container, item);
            }
            else
            {
                ContentControl control2 = element as ContentControl;
                if (control2 != null)
                {
                    this.PrepareContentControlForItem(control2, item);
                }
                else
                {
                    ContentPresenter presenter = element as ContentPresenter;
                    if (presenter != null)
                    {
                        this.PrepareContentPresenterForItem(presenter, item);
                    }
                    else
                    {
                        HierarchicalPresenter presenter2 = element as HierarchicalPresenter;
                        if (presenter2 != null)
                        {
                            presenter2.PrepareHierarchicalPresenterForItem(this, presenter2, item, base.ItemTemplate, this.ItemTemplateSelector, this.ItemContainerStyle, this.ItemContainerStyleSelector);
                        }
                        else
                        {
                            ItemsControl control3 = element as ItemsControl;
                            this.PrepareItemsControlForItem(control3, item);
                        }
                    }
                }
            }
            if (element.GetValue(FrameworkElement.StyleProperty) == null)
            {
                Style itemContainerStyle = this.ItemContainerStyle;
                if ((itemContainerStyle == null) && (this.ItemContainerStyleSelector != null))
                {
                    itemContainerStyle = this.ItemContainerStyleSelector.SelectStyle(item, element);
                }
                if (itemContainerStyle != null)
                {
                    element.SetValue(FrameworkElement.StyleProperty, itemContainerStyle);
                }
            }
            ItemPreparedEventArgs e = new ItemPreparedEventArgs
            {
                Element = element,
                Item = item
            };
            this.OnItemPrepared(e);
        }

        private void PrepareContentControlForItem(ContentControl container, object item)
        {
            if (container != item)
            {
                bool flag = true;
                if (base.ItemTemplate != null)
                {
                    container.ContentTemplate = base.ItemTemplate;
                }
                else if (this.ItemTemplateSelector != null)
                {
                    DataTemplate template = this.ItemTemplateSelector.SelectTemplate(item, container);
                    if (template != null)
                    {
                        container.ContentTemplate = template;
                    }
                }
                else if (!string.IsNullOrEmpty(base.DisplayMemberPath))
                {
                    Binding binding = new Binding(base.DisplayMemberPath);
                    container.SetBinding(ContentControl.ContentProperty, binding);
                    flag = false;
                }
                if (flag)
                {
                    container.Content = item;
                }
            }
        }

        private void PrepareContentPresenterForItem(ContentPresenter container, object item)
        {
            if (container != item)
            {
                bool flag = true;
                if (base.ItemTemplate != null)
                {
                    container.ContentTemplate = base.ItemTemplate;
                }
                else if (this.ItemTemplateSelector != null)
                {
                    DataTemplate template = this.ItemTemplateSelector.SelectTemplate(item, container);
                    if (template != null)
                    {
                        container.ContentTemplate = template;
                    }
                }
                else if (!string.IsNullOrEmpty(base.DisplayMemberPath))
                {
                    Binding binding = new Binding(base.DisplayMemberPath);
                    container.SetBinding(ContentPresenter.ContentProperty, binding);
                    flag = false;
                }
                if (flag)
                {
                    container.Content = item;
                }
            }
        }

        private void PrepareHeaderedContentControlForItem(HeaderedContentControl container, object item)
        {
            if (container != item)
            {
                if (base.ItemTemplate != null)
                {
                    container.HeaderTemplate = base.ItemTemplate;
                }
                else if (this.ItemTemplateSelector != null)
                {
                    DataTemplate template = this.ItemTemplateSelector.SelectTemplate(item, container);
                    if (template != null)
                    {
                        container.HeaderTemplate = template;
                    }
                }
                if (container.Content == null)
                {
                    container.Content = item;
                }
                if (!(item is UIElement) && (container.Header == null))
                {
                    container.Header = item;
                }
            }
        }

        internal void PrepareHierarchicalPresenterForItem(HierarchicalPresenter parent, HierarchicalPresenter container, object item, DataTemplate itemTemplate, DataTemplateSelector itemTemplateSelector, Style itemContainerStyle, StyleSelector itemContainerStyleSelector)
        {
            this.RootPresenter = (parent != null) ? parent.RootPresenter : null;
            this.ParentPresenter = parent;
            if ((container != item) && (this != item))
            {
                bool flag = true;
                if (itemTemplate != null)
                {
                    this.SetElementTemplate(itemTemplate, this);
                    if (base.ItemTemplate == null)
                    {
                        base.ItemTemplate = itemTemplate;
                    }
                }
                else if (itemTemplateSelector != null)
                {
                    DataTemplate template = itemTemplateSelector.SelectTemplate(item, this);
                    this.SetElementTemplate(template, this);
                    this.ItemTemplateSelector = itemTemplateSelector;
                }
                else if (!string.IsNullOrEmpty(base.DisplayMemberPath))
                {
                    Binding binding = new Binding(base.DisplayMemberPath);
                    base.SetBinding(HeaderProperty, binding);
                    flag = false;
                }
                if (flag)
                {
                    this.Header = item;
                }
            }
            if (itemContainerStyle != null)
            {
                this.ItemContainerStyle = itemContainerStyle;
            }
            if (itemContainerStyleSelector != null)
            {
                this.ItemContainerStyleSelector = itemContainerStyleSelector;
            }
        }

        private void PrepareItemsControlForItem(ItemsControl container, object item)
        {
            if (((container != item) && (this != item)) && (base.ItemTemplate != null))
            {
                container.ItemTemplate = base.ItemTemplate;
            }
        }

        private void SetCustomDefaultValues()
        {
        }

        private void SetElementTemplate(DataTemplate template, HierarchicalPresenter hp)
        {
            if (template != null)
            {
                DataTemplate template2 = template;
                HierarchicalDataTemplate template3 = template as HierarchicalDataTemplate;
                if (template3 != null)
                {
                    if (template3.ItemsSource != null)
                    {
                        hp.SetBinding(ItemsControl.ItemsSourceProperty, template3.ItemsSource);
                    }
                    if (template3.ItemTemplate != null)
                    {
                        hp.ItemTemplate = template3.ItemTemplate;
                    }
                }
                hp.HeaderTemplate = template2;
            }
        }

        public IList<T> ToList<T>() where T : HierarchicalPresenter
        {
            IList<T> list = new List<T>();
            this.ToList<T>(list, this);
            return list;
        }

        private IList<T> ToList<T>(IList<T> list, HierarchicalPresenter presenter) where T : HierarchicalPresenter
        {
            if (presenter != null)
            {
                foreach (object obj2 in presenter.Items)
                {
                    HierarchicalPresenter container = presenter.GetContainer(obj2);
                    if (container != null)
                    {
                        list.Add(container as T);
                        this.ToList<T>(list, container);
                    }
                }
            }
            return list;
        }

        // Properties
        internal bool ForceMouseOver
        {
            get { return (bool)GetValue(ForceMouseOverProperty); }
            set { SetValue(ForceMouseOverProperty, value); }
        }

        public bool HasItems
        {
            get { return Items.Count > 0; }
        }

        public object Header
        {
            get { return GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        public DataTemplate HeaderTemplate
        {
            get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        public bool IsMouseOver
        {
            get { return (bool)GetValue(IsMouseOverProperty); }
            set { SetValue(IsMouseOverProperty, value); }
        }

        public Style ItemContainerStyle
        {
            get { return (Style)GetValue(ItemContainerStyleProperty); }
            set { SetValue(ItemContainerStyleProperty, value); }
        }

        public StyleSelector ItemContainerStyleSelector
        {
            get { return (StyleSelector)GetValue(ItemContainerStyleSelectorProperty); }
            set { SetValue(ItemContainerStyleSelectorProperty, value); }
        }

        public TypeConverter ItemConverter
        {
            internal get
            {
                if (this._itemConverter == null)
                    return new HierarchicalPresenterConverter();

                return this._itemConverter;
            }
            set { this._itemConverter = value; }
        }

        public DataTemplateSelector ItemTemplateSelector
        {
            get { return (DataTemplateSelector)GetValue(ItemTemplateSelectorProperty); }
            set { SetValue(ItemTemplateSelectorProperty, value); }
        }

        public IList ParentCollection
        {
            get
            {
                if (this.ParentPresenter != null)
                    return this.ParentPresenter.Items;

                return null;
            }
        }

        public IEnumerable ParentItemsSource
        {
            get
            {
                if (this.ParentPresenter != null)
                    return this.ParentPresenter.ItemsSource;

                return null;
            }
        }

        internal HierarchicalPresenter ParentPresenter { get; set; }

        internal HierarchicalPresenter RootPresenter
        {
            get
            {
                if (this._rootPresenter == null && this.ParentPresenter != null)
                    this._rootPresenter = this.ParentPresenter.RootPresenter;

                return this._rootPresenter;
            }
            set { this._rootPresenter = value; }
        }
    }
}
